package com.dlyk.aspect;

import com.dlyk.commons.DataScope;
import com.dlyk.constant.Constants;
import com.dlyk.model.User;
import com.dlyk.query.BaseQuery;
import com.dlyk.util.JWTUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.List;

@Aspect
@Component
public class DataScopeAspect {

    // aspectJ 实现aop

    // 切入点
    @Pointcut(value = "@annotation(com.dlyk.commons.DataScope)")
    private void pointCut() {

    }

    // 环绕增强
    @Around(value = "pointCut()")
    public Object process(ProceedingJoinPoint joinPoint) throws Throwable {

        // 通过请求上下文持有器获取Request对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        // 通过request对象获取请求头中的token
        String token = request.getHeader(Constants.TOKEN_NAME);

        // 从token中解析出当前登录的用户
        User user = JWTUtils.parseUserFromJWT(token);

        // 获取用户角色
        List<String> roleList = user.getRoleList();

        // 判断当前用户是否是管理员
        // 管理员：查询所有数据，sql语句不用拼接过滤条件
        // 普通用户：只查询当前用户自己的数据，sql语句需要拼接过滤条件
        boolean admin = roleList.contains("admin");
        if (!admin) {
            // 获取方法的第一个参数
            Object params = joinPoint.getArgs()[0];
            // 判断第一个参数的类型，如果是BaseQuery类型，则表明该方法的sql需要拼接
            if (params instanceof BaseQuery) {
                // 强制类型转换
                BaseQuery baseQuery = (BaseQuery) params;

                // 获取方法签名
                MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

                // 通过方法签名获取方法，然后通过方法获取方法上的@DataScope注解
                DataScope dataScope = methodSignature.getMethod().getDeclaredAnnotation(DataScope.class);

                // 表的别名
                String tableAlias = dataScope.tableAlias();
                // 表的字段
                String tableField = dataScope.tableField();

                // select * from user u
                // 设置需要拼接的内容：and where u.id = 2
                // select * from user u where u.id = 2
                baseQuery.setFilterSQL(" and " + tableAlias + "." + tableField + " = " + user.getId());
                // 在mapper文件中使用<where>标签，标签体中的内容如果是以and或者or开头，会自动去掉
                // 这里拼接的内容放到sql末尾，所以加上and，防止前面有其他where子句的时候报错
            }
        }

        // 目标方法执行前

        // 执行目标方法
        Object result = joinPoint.proceed();

        // 目标方法执行后

        return result;
    }

}

